﻿using System.Text.Json;
using System.Text.Json.Serialization;
using System.Xml.Linq;

namespace LightCAD.Core.Elements
{
    /// <summary>
    /// 组件实例引用
    /// </summary>
    public class LcComponentRef : LcElement,IComponenetElement
    {
        /// <summary>
        /// 组件外形
        /// </summary>
        public List<ICurve2d> ShapeCurves { get; } = new List<ICurve2d>();
        public LcComponent Component { get; set; }

        public List<AssociatePoint> AssociatePoints => throw new NotImplementedException();

        public List<AssociateElement> AssociateElements => throw new NotImplementedException();

        public string Material { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
        public string MaterialSettings { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

        private Vector2d? insertPoint;

        public Vector2d InsertPoint
        {
            get
            {
                if (insertPoint == null)
                {
                    insertPoint = Matrix.GetTranslateVector();
                }
                return insertPoint.Value;
            }
            set
            {
                OnPropertyChangedBefore(nameof(insertPoint),insertPoint,value);
                insertPoint = value;
                OnPropertyChangedAfter(nameof(insertPoint), insertPoint, value);
            }
        }
        public virtual Matrix3d Matrix { get; set; }

        private Matrix3d? matrixInverse;

        public Matrix3d MatrixInverse
        {
            get
            {
                if (matrixInverse == null)
                {
                    matrixInverse = Matrix.Inverse();
                }
                return matrixInverse.Value;
            }
        }

        public LcComponentRef()
        {
        }


        public override LcElement Clone()
        {
            var clone = new LcComponentRef();
            clone.Copy(this);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            var comref = ((LcComponentRef)src);
            this.InsertPoint = comref.InsertPoint.Clone();
            this.Matrix = comref.Matrix.Clone();
        }

        public virtual void Invoke(string methodName, InvokeToken token)
        {
        }

        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            base.WriteProperties(writer, soptions);
        }
        public override void ReadProperties(ref JsonElement jele)
        {
            base.ReadProperties(ref jele);
        }
        public override void Scale(Vector2d basePoint, double scaleFactor)
        {
            Matrix3d scaleMatrix = Matrix3d.Scale(scaleFactor, basePoint);
            this.Set(matrix: scaleMatrix * this.Matrix);
            Reset();
        }
        public override void Rotate(Vector2d basePoint, double rotateAngle)
        {
            Matrix3d rotateMatrix = Matrix3d.RotateInRadian(rotateAngle, basePoint);
            this.Set(matrix: rotateMatrix * this.Matrix);
            Reset();
        }
        public override void Mirror(Vector2d axisStart, Vector2d axisEnd)
        {
            Matrix3d mirrorMatrix = Matrix3d.Mirror(axisEnd, axisStart);
            this.Set(matrix: mirrorMatrix * this.Matrix);
            Reset();
        }
        public override void Move(Vector2d startPoint, Vector2d endPoint)
        {
            Matrix3d matrix3 = Matrix3d.Move(startPoint, endPoint);
            this.Set(matrix: matrix3 * this.Matrix);
            Reset();
        }
        public override void Translate(double dx, double dy)
        {
            this.Set(matrix: Matrix3d.Translate(dx, dy) * Matrix);
            Reset();
        }
        public void Set(
           Matrix3d? matrix = null,
           bool fireChangedEvent = true)
        {
            //PropertySetter:Center,Radius            
            if (!fireChangedEvent)
            {
                if (matrix != null) this.Matrix = matrix.Value;
            }
            else
            {
                bool chg_matrix = (matrix != null && matrix != this.Matrix);
                if (chg_matrix)
                {
                    OnPropertyChangedBefore(nameof(Matrix), this.Matrix, matrix);
                    var oldValue = this.Matrix;
                    this.Matrix = matrix.Value;
                    OnPropertyChangedAfter(nameof(Matrix), oldValue, this.Matrix);
                }
            }
        }
        public void Reset()
        {
            ResetBoundingBox();
            matrixInverse = null;
            insertPoint = null;

        }
    }
}
